/*
 * Created on Dec 19, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package dbsucxentW.constructW;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.Vector;

import javax.swing.tree.DefaultMutableTreeNode;

/**
 * @author Lee Tzyy Ming
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
// Reconstruction for Edge

public class ReconstructEdge{
	ResultSet _results;
//	String _path; 
//	String[] _paths, _oldPaths;
	String _unsplitPaths[];
	String _paths[][];
	boolean _pathIsAttribute[];
	Vector _attribute = new Vector();
	//Vector _atttributeValue = new Vector();
	int _pathID, _oldPathID;
	long _deweyOrderSum, _oldDeweyOrderSum;
	long[] _rValue;
	Connection _dbConnection;
	FileOutputStream fileOutputStream;
	StringBuilder stringResult;
	DefaultMutableTreeNode top;
	DefaultMutableTreeNode current;
	public final int TREE = 1, TEXT = 2, FILE = 3;
	int _output = 0, _level = 0;
	Timer timer;
	String _startElement, rootName = "results";
	Statement statement;
	long rowCount = 0;
	long leafCount = 0;
	private long sTime;
	private long eTime;
	private long period;
	private long temp;
	private long otherTime=0;
	private long resultTime=0;
	private long statementTime=0;
	
	
	public ReconstructEdge(ResultSet results, Connection dbConnection){
		_results = results;
		_dbConnection = dbConnection;
	}
	
	public void reconstructFile(String filename) throws FileNotFoundException, SQLException, IOException {
		_output = FILE;
		
		if (filename.trim().equals("")) filename = "queryResults";
		File file = new File(filename + ".xml");
		fileOutputStream = new FileOutputStream(file);

		fileOutputStream.write(("<" + rootName + ">").getBytes());
		reconstruct();
		fileOutputStream.write(("</" + rootName + ">").getBytes());

		fileOutputStream.close();
		
		openFile(filename);
	}
	
	public String reconstructText() throws FileNotFoundException, SQLException, IOException {
		timer = new Timer();
		stringResult = new StringBuilder();
		_output = TEXT;

		stringResult.append("<" + rootName + ">");
		reconstruct();
		stringResult.append("</" + rootName + ">");

		return stringResult.toString();
	}
	
	public DefaultMutableTreeNode reconstructTree() throws FileNotFoundException, SQLException, IOException {
		timer = new Timer();
		_output = TREE;
		top = new DefaultMutableTreeNode(rootName);
		current = top;
		reconstruct();
		return top;
	}
	
	private String[] getPath(int pathID) {
		if (_paths[pathID-1] == null) { 
			setPath(pathID);
		}
		return _paths[pathID-1];
	}

	private boolean isPathAttribute(int pathID) {
		if (_paths[pathID-1] == null) { 
			setPath(pathID);
		}
		return _pathIsAttribute[pathID-1];
	}
	
	private void setPath(int pathID) {
	_paths[pathID-1] = _unsplitPaths[pathID-1].split("\\.");
	int i = 1;
	//for (; i < _paths[pathID-1].length; i++)
	//	_paths[pathID-1][i] = _paths[pathID-1][i].trim();
	_paths[pathID-1][_paths[pathID-1].length-1]=_paths[pathID-1][_paths[pathID-1].length-1].trim();
	for (i=1; i < _paths[pathID-1].length; i++)
		_paths[pathID-1][i] = _paths[pathID-1][i].substring(0, (_paths[pathID-1][i]).length() - 1);
	char lastElement = _paths[pathID-1][i-1].charAt(0);
	if(lastElement == '@') _pathIsAttribute[pathID-1] = true;
	else _pathIsAttribute[pathID-1] = false;
	}
	
	public void reconstruct() throws FileNotFoundException, SQLException, IOException {
		_unsplitPaths = getPaths(_dbConnection);
    	//timer.setTimer("endOfGetPath    ");
		_paths = new String[_unsplitPaths.length][];
		_pathIsAttribute = new boolean[_unsplitPaths.length];

		_results.first();
		try {
			_pathID = _results.getInt(2);
		} catch (SQLException e){
			/*
			if (_output == TREE) {
				top = new DefaultMutableTreeNode("Root");
				current = top;
			}
			*/
			writeLeaf("No results");
			return;
		}
		_results.beforeFirst();
		
		//statement = _dbConnection.createStatement (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);

    	sTime = System.nanoTime();

		construct(_results);
		
		System.out.println("ResultSet Time:"+ resultTime);
		System.out.println("Statement Time:"+ statementTime);
		System.out.println("Other Time:"+ otherTime);
	}
	
	private long getPeriod() {
		eTime = System.nanoTime();
		period = eTime-sTime;
		sTime = eTime;
		return period;
	}
	
	private boolean construct(ResultSet inResult) throws FileNotFoundException, SQLException, IOException {
		int pathID;
		int id;
		String elementValue;
		String elementName;
		
		temp = getPeriod();
		//if (temp > 0)
		//	System.out.println("B4 statement:" + temp);
		otherTime += temp;
		
		Statement statement = _dbConnection.createStatement (ResultSet.TYPE_FORWARD_ONLY,
				ResultSet.CONCUR_READ_ONLY);

		temp = getPeriod();
		//if (temp > 0)
		//	System.out.println("Statement:" + temp);
		statementTime += temp;

		boolean haveResult = false;
		while(inResult.next()) {
			haveResult = true;
			elementValue = inResult.getString(1);
			pathID = inResult.getInt(2);
			id = inResult.getInt(3);
			elementName = getPath(pathID)[getPath(pathID).length - 1];
			
			if (isPathAttribute(pathID) == false) {
				startElement(elementName);

				temp = getPeriod();
				//if (temp > 0)
				//	System.out.println("B4 ResultSet:" + temp);
				otherTime += temp;
				ResultSet outResult = statement.executeQuery ("SELECT value, path_id, id FROM Edge WHERE parent_id =" + id + " ORDER BY id"); 
				//ResultSet outResult = statement.executeQuery ("SELECT value, path_id, id FROM Edge WHERE parent_id =" + id); 
				temp = getPeriod();
				//if (temp > 0)
				//	System.out.println("ResultSet:" + temp);

				resultTime += temp;
				boolean haveChild = construct(outResult);

				
				if (elementValue != null) {
					writeLeaf(elementValue.trim());
					leafCount++;
				} else if (!haveChild) {
					leafCount++;
				}
				
			
				
				endElement(elementName);
			}
			else {
				leafCount++;
				String attributeName = getPath(pathID)[getPath(pathID).length - 1];
				attributeName = attributeName.substring(1, attributeName.length());
				if (elementValue != null)
					writeAttribute(attributeName + " = '" + elementValue.trim() + "'");
				else 
					writeAttribute(attributeName + " = ' '");
			}
			
			rowCount++;
		}
		return haveResult;
		
	}
	
	
/*	old version, use pathexp instead of pathid	
	public void reconstruct() throws FileNotFoundException, SQLException, IOException {
		int newBranchOrder;
		
		_rValue = getRValue(_dbConnection);

		_results.first();
		_path = _results.getString(2);
		_paths = _path.split("\\.");
		
		int j = 1;
		if (_output == TREE) {
			top = new DefaultMutableTreeNode(_paths[1].trim());
			current = top;
			j++;
		}
		
		for (; j<_paths.length; j++) {
			startElement(_paths[j].trim());
		}
		
		_oldDeweyOrderSum = 0;
		_oldPaths = _paths;
		writeLeaf(_results.getString(1).trim());

		
		while (_results.next()) {
			_path = _results.getString(2);
			_paths = _path.split("\\.");
			
			_deweyOrderSum = _results.getInt(4);
			
			long deweyDiff = _deweyOrderSum - _oldDeweyOrderSum;
			for (newBranchOrder=_results.getInt(3)-2; newBranchOrder>=0; newBranchOrder--) {
				if (deweyDiff < _rValue[newBranchOrder]) break; 
			}
			newBranchOrder+=2;
			
			for (int i=_oldPaths.length-1; i>newBranchOrder; i--) {
				endElement(_oldPaths[i].trim());
			}
			
			for (int i=newBranchOrder+1; i<_paths.length; i++) {
				startElement(_paths[i].trim());
			}
			
			writeLeaf(_results.getString(1).trim());

			_oldDeweyOrderSum = _deweyOrderSum;
			_oldPaths = _paths;
		}		
		
		for (int i=_oldPaths.length-1; i>0; i--) {
			endElement(_oldPaths[i].trim());
		}
	}
*/	
	
	public static void openFile(String filename) throws IOException{
		Runtime rt = Runtime.getRuntime();
		
		String[] cmd = new String[4];
		cmd[0] = "cmd.exe";
		cmd[1] = "/C";
		cmd[2] = "start";
		cmd[3] = filename + ".xml";
	
		Process p = rt.exec(cmd);
	}
	
	private void writeAttribute(String attribute) {
		_attribute.add(attribute);
	}
	
	private void startElement(String element) throws IOException {
		writeStartElement();
		_startElement = element; 
	}

	private void writeStartElement() throws IOException{
		//if (element.trim().equals("")) return;
		String attribute;
		if (_startElement == null) return;
		if (_output == FILE) {
			fileOutputStream.write('<');
			fileOutputStream.write(_startElement.getBytes());
			for (int i=0; i<_attribute.size(); i++) {
				attribute = "  " + (String)_attribute.elementAt(i);
				fileOutputStream.write(attribute.getBytes());
			}
			fileOutputStream.write('>');
		} else if (_output == TEXT) {
			//for (int i=0; i < _level; i++)
			//	stringResult.append("      ");
			
			stringResult.append("<" + _startElement);
			for (int i=0; i<_attribute.size(); i++) 
				stringResult.append("  " + (String)_attribute.elementAt(i));
			
			//stringResult.append(">\n");
			stringResult.append(">");
			_level++;
		} else {	// (output == TREE)
			for (int i=0; i<_attribute.size(); i++) 
				_startElement += "  " + (String)_attribute.elementAt(i);
			
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(_startElement);
			current.add(node);
			current = node;
		}	
		_attribute.clear();
		_startElement = null;
	}
	
	private void endElement(String element) throws IOException {
		//if (element.trim().equals("")) return;
		writeStartElement();
		if (_output == FILE) {
			fileOutputStream.write('<');
			fileOutputStream.write('/');
			fileOutputStream.write(element.getBytes());
			fileOutputStream.write('>');
		} else if (_output == TEXT) {
			_level--;
			//for (int i=0; i < _level; i++)
				//stringResult.append("      ");
			
			//stringResult.append("</" + element + ">\n");
			stringResult.append("</" + element + ">");
		} else {	// (output == TREE)
			current = (DefaultMutableTreeNode) current.getParent();
		}
	}
	
	private void writeLeaf(String leaf) throws IOException {
		writeStartElement();
		if (_output == FILE) {
			fileOutputStream.write(leaf.getBytes());
		} else if (_output == TEXT) {
			//for (int i=0; i < _level; i++)
				//stringResult.append("      ");
			
			//stringResult.append(leaf + "\n");
			stringResult.append(leaf);
		} else {	// (output == TREE)
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(leaf);
			current.add(node);
		}
	}
	
/*	
	public long[] getRValue(Connection dbConnection) throws SQLException {
		int docId = 1;
		long[] rvalue;
		
		Statement statement = _dbConnection.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                				ResultSet.CONCUR_READ_ONLY);
		//ResultSet results = statement.executeQuery ("SELECT RValue FROM DocumentRValue WHERE DocId=" + docId + " ORDER BY Level"); 
    	timer.setTimer("statementIntialize");
		ResultSet results = statement.executeQuery ("SELECT RValue FROM DocumentRValue WHERE DocId=" + docId); 
		//ResultSet results = statement.executeQuery ("SELECT RValue FROM DocumentRValue"); 
		
    	timer.setTimer("pathExecuteQuery");
		results.last();
		rvalue = new long[results.getRow()];
		results.beforeFirst();
		
		for(int i=0; results.next(); i++) {
			rvalue[i] = results.getLong(1);
		}
		
		results.close();											
		statement.close();											
 
		return rvalue;
	}
*/
	
	public String[] getPaths(Connection dbConnection) throws SQLException {
		int docId = 1;
		String[] unsplitPaths;
		
		Statement statement1 = _dbConnection.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                				ResultSet.CONCUR_READ_ONLY);	// ms sql server 2005
		//Statement statement1 = _dbConnection.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
		//		ResultSet.CONCUR_UPDATABLE);	// ms sql server 2000
		
    	//timer.setTimer("statementIntialize");
		ResultSet results = statement1.executeQuery ("SELECT path FROM Path ORDER BY path_id"); 
    	//timer.setTimer("pathExecuteQuery");
		
		results.last();
		unsplitPaths = new String[results.getRow()];
		results.beforeFirst();
		
		for(int i=0; results.next(); i++) {
			unsplitPaths[i] = results.getString(1);
		}
		
		results.close();											
		statement1.close();											
 
		return unsplitPaths;
	}
	
	public long getProcessedRows() {
		return rowCount;
	}
	
	public long getLeafCount(){
		return leafCount;
	}
}
